/*
<Copyright (C) 2011 Dru Moore>

This file is part of demorecorder.

vlc-remote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

demorecorder is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with demorecorder.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "demorecorder.h"
#include "utilities.h"
#include <QDebug>
#include <QDir>

DemoRecorder::DemoRecorder(QObject *parent) {
    DemoRecorder::DemoRecorder(parent, NULL);
}

DemoRecorder::DemoRecorder(QObject *parent, QDeclarativeContext *context) :
    QObject(parent)
{
    this->context = context;
    //this->trackListModel = TrackListModel();
    this->playhead_position = 0;
    this->playhead_duration = 0;
    this->recorder_position = 0;
    this->recorder_duration = 0;
    this->pipeline = NULL;
    this->recordpipeline = NULL;
    this->composition = NULL;
    this->projectFolderPath = Utilities::getHomeDirectory() + "/MyDocs/demorecorder/projects/default/"; //"/home/user/MyDocs/demorecorder/projects/default/"; // Utilities::getHomeDirectory() + "/MyDocs/demorecorder/projects/default/";
    if (!Utilities::doesDirectoryExist(this->projectFolderPath)) {
        Utilities::createAllDirectories(this->projectFolderPath); // Should check return!
    }
    QStringList(this->tracks);
    QList<SimpleTrack*>(this->simpletracks);
    this->loadProjectTracks();

    // set tracklist model
    /*this->trackListModel.addTrackListItem(TrackListItem("track1", "Track One", "audio", "#cc0000", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track2", "Track Two", "favourite", "#00cc00", true, false));
    this->trackListModel.addTrackListItem(TrackListItem("track3", "Track Three", "heart", "#0000cc", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track4", "Track Four", "audio", "#cccc00", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track5", "Track Five", "audio", "#cc00cc", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track6", "Track Six", "audio", "#00cccc", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track7", "Track Seven", "audio", "#cccccc", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track8", "Track Eight", "audio", "#cc00cc", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track9", "Track Nine", "audio", "#cccccc", false, true));
    this->trackListModel.addTrackListItem(TrackListItem("track10", "Track Ten", "audio", "#cc0000", false, true));*/
    if (NULL != context) {
        context->setContextProperty("trackListModel", &this->trackListModel);
    }
    // should we get the track list
    this->createPipeline ();
}

void DemoRecorder::loadProjectTracks() {
    // this->projectFolderPath
    QDir dir(this->projectFolderPath);
    dir.setSorting(QDir::Name);
    dir.setFilter(QDir::NoDotAndDotDot | QDir::Files);
    QFileInfoList list = dir.entryInfoList();
    for (int idx; idx < list.size(); ++idx) {
        QFileInfo fileInfo = list.at(idx);
        this->trackListModel.addTrackListItem(TrackListItem("track" + QString::number(idx), "Track " + QString::number(idx), "audio", "#cc0000", true, true));
        SimpleTrack *track = new SimpleTrack(this, QString::number(idx), fileInfo.absoluteFilePath(), 0, 60 * GST_SECOND, 0, 60 * GST_SECOND);
        this->simpletracks.append(track);
    }
}

void DemoRecorder::play () {
    if (!this->pipeline) {
        qDebug("creating playpipeline!");
        this->createPipeline ();
    }
    if (this->pipeline) {
        qDebug("playing?");
        this->pipeline->play();
        this->timer = new QTimer(this);
        QObject::connect(this->timer, SIGNAL(timeout()), this->pipeline, SLOT(get_duration_info()));
        this->timer->start(100);
    }
    else {
        qDebug("No playpipeline after create!");
    }
    //QModelIndex index = this->trackListModel.index(1, 0, QModelIndex());
    //this->trackListModel.setData(index, "I changed", TrackListModel::TitleRole);
}
void DemoRecorder::stop () {
    if (this->pipeline) {
        this->pipeline->pause();
        this->timer->stop();
    }
}
void DemoRecorder::pause () {
    if (this->pipeline) {
        this->pipeline->pause();
        this->timer->stop();
    }
}
void DemoRecorder::rewind() {
    this->pipeline->seekTo(0);
}
void DemoRecorder::advance() {
    this->pipeline->seekTo(0);
}
void DemoRecorder::record () {
    if (!this->recordpipeline) {
        this->createRecordPipeline ();
        this->recorder_timer = new QTimer(this);
        QObject::connect(this->recorder_timer, SIGNAL(timeout()), this->recordpipeline, SLOT(get_duration_info()));
        this->recorder_timer->start(100);
    }
    if (this->recordpipeline) {
        this->recordpipeline->record();
    }
    else {
        qDebug("No recordpipeline after create!");
    }
}
void DemoRecorder::stoprecording () {
    if (this->recordpipeline) {
        this->recordpipeline->stop();
        this->recorder_timer->stop();
        int track_no = this->trackListModel.rowCount();
        this->trackListModel.addTrackListItem(TrackListItem("track" + QString::number(track_no), "Track " + QString::number(track_no), "audio", "#cc0000", true, true));
        SimpleTrack *track = new SimpleTrack(this, QString::number(track_no), this->current_file, 0, 60 * GST_SECOND, 0, 60 * GST_SECOND);
        this->simpletracks.append(track);
    }
    //delete this->recordpipeline;
    teardownRecordPipeline();
}

void DemoRecorder::setProjectFolder(const QString &path) {
    this->projectFolderPath.append(path);
    qDebug() << this->projectFolderPath;
}

QString DemoRecorder::getMyString(const QString &text) const {
    QString ret = "returned";
    qDebug() << text;
    return ret;
}

void DemoRecorder::eos_handler() {
    qDebug() << "eos signalled";
    this->pipeline->stop();
    this->timer->stop();
    emit this->playbackEnded();
}

void DemoRecorder::recorder_eos_handler() {
    qDebug() << "recorder eos signalled";
    this->recordpipeline->stop();
    this->recorder_timer->stop();
    emit this->recordingEnded();
}

void DemoRecorder::position_duration_handler(long long position, long long duration) {
    this->playhead_position = position;
    this->playhead_duration = duration;
    //qDebug() << "position: " << QString::number((double)(position / 100000000ll) / 10) << " duration: " << QString::number((double)(duration / 100000000ll) / 10);
}

void DemoRecorder::recorder_position_duration_handler(long long position, long long duration) {
    //qDebug() << "recorder_position_duration_handler got called! " << position << " " << duration;
    this->recorder_position = position;
    this->recorder_duration = duration;
    //qDebug() << "position: " << QString::number((double)(position / 100000000ll) / 10) << " duration: " << QString::number((double)(duration / 100000000ll) / 10);
}

long DemoRecorder::getPlayheadPosition() const {
    return (this->playhead_position / 1000000);
}
long DemoRecorder::getPlayheadDuration() const {
    return (this->playhead_duration / 1000000);
}
long DemoRecorder::getRecorderPosition() const {
    return (this->recorder_position / 1000000);
}

void DemoRecorder::createPipeline () {
    this->pipeline = new MixerPipeline::MixerPipeline(this, "Mixer");
    foreach (SimpleTrack* track, this->simpletracks) {
        qDebug() << "Track added? " << this->pipeline->add_track(track->getName(), track->getTrackBin());
    }

    //GstElement *audioOutput = gst_element_factory_make ("autoaudiosink", "output");

    //this->pipeline = new PlayPipeline("pipeline", this->simpletracks.at(1)->getTrackBin(), audioOutput, true);

    /*
    // Should convert this to use a Composition
    this->composition = new Composition("Playback");

    qDebug() << "adding file src: " << this->composition->addFileSource("Test2", "file:///home/user/MyDocs/Music/PJ Harvey/Dry/PJ Harvey - Hair.mp3", 12 * GST_SECOND, 22 * GST_SECOND, 25 * GST_SECOND, 22 * GST_SECOND,1);
    qDebug() << "adding file src: " << this->composition->addFileSource("Test1", "file:///home/user/MyDocs/Music/PJ Harvey/Dry/PJ Harvey - Fountain.mp3", 0, 12 * GST_SECOND, 0, 12 * GST_SECOND,2);
    GstElement *audioSrc = this->composition->getComposition();
    g_assert(audioSrc);

    GstElement *audioSinkBin = gst_bin_new("PlaybackSink");
    g_assert(audioSinkBin);

    GstElement *audioConverter = gst_element_factory_make ("audioconvert", "converter");
    g_assert(audioConverter);

    GstElement *audioOutput = gst_element_factory_make ("autoaudiosink", "output");
    g_assert(audioOutput);

    gst_bin_add_many(GST_BIN(audioSinkBin), audioConverter, audioOutput, NULL);

    gst_element_link(GST_ELEMENT(audioConverter), GST_ELEMENT(audioOutput));

    GstPad *sinkConverterPad = gst_ghost_pad_new("sink", gst_element_get_static_pad(audioConverter, "sink"));
    //qDebug() << "adding ghost pads";
    gst_element_add_pad(audioSinkBin, sinkConverterPad);
    //qDebug() << "ghost pads added";

    this->pipeline = new PlayPipeline("player", audioSrc, audioSinkBin, false);
    */

    QObject::connect(this->pipeline, SIGNAL(end_of_stream()), this, SLOT(eos_handler()));
    QObject::connect(this->pipeline, SIGNAL(position_duration(long long,long long)), this, SLOT(position_duration_handler(long long,long long)));

    this->pipeline->pause(); // for ready state

    emit this->pipelineReady(); // tell anyone who's interested that we are good to go.

}


void DemoRecorder::createRecordPipeline () {
///home/user/MyDocs/Music/test.ogg
    GstElement *audioSrc = gst_element_factory_make("pulsesrc", "source");
    g_assert(audioSrc);

    GValue loc = {0, };
    g_value_init (&loc, G_TYPE_STRING);
    //g_value_set_string(&loc, "http://bbcmedia.ic.llnwd.net/stream/bbcmedia_lc1_radio4_q?s=1311366348&e=1311380748&h=ef6dd3c942f970942a66cfec0a2bad08"); //file:///home/user/MyDocs/Music/PJ Harvey/Dry/PJ Harvey - Dress.mp3");
    //g_value_set_string(&loc, "file:///home/user/MyDocs/Music/PJ Harvey/Dry/PJ Harvey - Dress.mp3"); //file:///home/user/MyDocs/Music/PJ Harvey/Dry/PJ Harvey - Dress.mp3");
    //g_object_set_property(G_OBJECT(audioSrc), "uri", &loc);

    qDebug() << "get caps";
    GstCaps *caps = gst_caps_from_string("audio/x-raw-float,rate=48000,channels=2,width=32");

    this->current_file = Utilities::getNextAvailableFileName(this->projectFolderPath + "track-001.wav");

    this->recordpipeline = new RecordPipeline("recorder", this->current_file, audioSrc, caps, "wavenc");
    qDebug() << "recordpipelne new returned";

    //delete caps;

    QObject::connect(this->recordpipeline, SIGNAL(end_of_stream()), this, SLOT(recorder_eos_handler()));
    QObject::connect(this->recordpipeline, SIGNAL(position_duration(long long,long long)), this, SLOT(recorder_position_duration_handler(long long,long long)));

    /*this->pipeline = gst_pipeline_new ("pipeline");
    g_assert(this->pipeline);


    GstElement *audioOut = gst_element_factory_make("autoaudiosink", "audio out");
    g_assert(audioOut);

    gst_bin_add_many(GST_BIN(this->pipeline), audioSrc, audioOut, NULL);
    gst_element_link_many(audioSrc, audioOut, NULL);*/

}

void DemoRecorder::teardownRecordPipeline() {
    // should clena up here.
    //qDebug() << "In teardownRecordPipeline, calling delete";
    delete this->recordpipeline;
    //qDebug() << "In teardownRecordPipeline, post delete, setting NULL";
    this->recordpipeline = NULL;
}

void DemoRecorder::trackToggleActive(const int idx, bool active) {
    this->trackToggleMute(idx, active);
//    this->stop();
//    SimpleTrack* track = this->simpletracks.at(idx);
//    qDebug() << "In trackToggleActive, idx: " << idx << " active: " << active;
//    if (active) {
//        this->pipeline->add_track(track->getName(), track->getTrackBin());
//    }
//    else {
//        this->pipeline->remove_track(track->getName());
//    }
}

void DemoRecorder::trackToggleMute(const int idx, bool mute) {
    ((SimpleTrack*)this->simpletracks.at(idx))->setMute(mute);
}

void DemoRecorder::trackSetVolume(const int idx, double volume) {
    ((SimpleTrack*)this->simpletracks.at(idx))->setVolume(volume);
}

void DemoRecorder::trackSetPanorama(const int idx, double panorama) {
    ((SimpleTrack*)this->simpletracks.at(idx))->setPanorama(panorama);
}
